package cn.feng.thinkInJava.a9_2_泛型.generics.a15_15_04;

//: generics/DynamicProxyMixin.java
import java.lang.reflect.*;
import java.util.*;

import net.mindview.util.*;
import static net.mindview.util.Tuple.*;

/**
 * 与动态代理混合
 * 
 * @author fengyu
 * @date 2015年8月9日
 */
class MixinProxy implements InvocationHandler
{
	Map<String,Object> delegatesByMethod;
	
	public MixinProxy(TwoTuple<Object,Class<?>>...pairs)
	{
		delegatesByMethod=new HashMap<String,Object>();
		for(TwoTuple<Object,Class<?>> pair:pairs)
		{
			for(Method method:pair.second.getMethods())
			{
				String methodName=method.getName();
				// The first interface in the map
				// implements the method.
				if(!delegatesByMethod.containsKey(methodName))
					delegatesByMethod.put(methodName,pair.first);
			}
		}
	}
	
	public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
	{
		String methodName=method.getName();
		Object delegate=delegatesByMethod.get(methodName);
		return method.invoke(delegate,args);
	}
	
	@SuppressWarnings("unchecked")
	public static Object newInstance(TwoTuple...pairs)
	{
		Class[] interfaces=new Class[pairs.length];
		for(int i=0;i<pairs.length;i++)
		{
			interfaces[i]=(Class)pairs[i].second;
		}
		ClassLoader cl=pairs[0].first.getClass().getClassLoader();
		return Proxy.newProxyInstance(cl,interfaces,new MixinProxy(pairs));
	}
}

public class DynamicProxyMixin
{
	public static void main(String[] args)
	{
		Object mixin=MixinProxy.newInstance(tuple(new BasicImp(),Basic.class),tuple(new TimeStampedImp(),TimeStamped.class),
				tuple(new SerialNumberedImp(),SerialNumbered.class));
		Basic b=(Basic)mixin;
		TimeStamped t=(TimeStamped)mixin;
		SerialNumbered s=(SerialNumbered)mixin;
		b.set("Hello");
		System.out.println(b.get());
		System.out.println(t.getStamp());
		System.out.println(s.getSerialNumber());
	}
} /*
 * Output: (Sample) Hello 1132519137015 1
 */// :~

interface TimeStamped
{
	long getStamp();
}

class TimeStampedImp implements TimeStamped
{
	private final long timeStamp;
	
	public TimeStampedImp()
	{
		timeStamp=new Date().getTime();
	}
	
	public long getStamp()
	{
		return timeStamp;
	}
}

interface SerialNumbered
{
	long getSerialNumber();
}

class SerialNumberedImp implements SerialNumbered
{
	private static long counter=1;
	private final long serialNumber=counter++;
	
	public long getSerialNumber()
	{
		return serialNumber;
	}
}

interface Basic
{
	public void set(String val);
	
	public String get();
}

class BasicImp implements Basic
{
	private String value;
	
	public void set(String val)
	{
		value=val;
	}
	
	public String get()
	{
		return value;
	}
}

class Mixin extends BasicImp implements TimeStamped,SerialNumbered
{
	private TimeStamped timeStamp=new TimeStampedImp();
	private SerialNumbered serialNumber=new SerialNumberedImp();
	
	public long getStamp()
	{
		return timeStamp.getStamp();
	}
	
	public long getSerialNumber()
	{
		return serialNumber.getSerialNumber();
	}
}
